package com.android.tnovoselec.travelassistant.async;

import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.Callable;

import android.content.Context;
import android.util.Log;

import com.android.tnovoselec.travelassistant.Config;
import com.android.tnovoselec.travelassistant.dto.BenzinskaDto;
import com.android.tnovoselec.travelassistant.dto.BenzinskeResultHolder;
import com.google.android.maps.GeoPoint;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;

public class BenzinskeRefresher implements Callable<Boolean> {

	private static final double LONG_SCALE_DE_APPROX = Math.cos(Math.toRadians(50)); // 50
	// latitude

	private final Context context;
	private final Dao<BenzinskaDto, String> benzinskaDao;
	private final GeoPoint geoPointTopLeft;
	private final GeoPoint geoPointBottomRight;
	private GeoPoint middlePoint;
	private String activeType;

	private final double latitudeTopLeft;
	private final double longitudeTopLeft;
	private final double latitudeBottomRight;
	private final double longitudeBottomRight;

	public BenzinskeRefresher(Context context, Dao<BenzinskaDto, String> benzinskaDao, GeoPoint geoPointTopLeft, GeoPoint geopointBottomRight, String activeType) {
		super();
		this.context = context;
		this.benzinskaDao = benzinskaDao;
		this.geoPointTopLeft = geoPointTopLeft;
		this.geoPointBottomRight = geopointBottomRight;
		this.activeType = activeType;

		latitudeTopLeft = geoPointTopLeft.getLatitudeE6() / 1E6D;
		longitudeTopLeft = geoPointTopLeft.getLongitudeE6() / 1E6D;

		latitudeBottomRight = geoPointBottomRight.getLatitudeE6() / 1E6D;
		longitudeBottomRight = geoPointBottomRight.getLongitudeE6() / 1E6D;

		middlePoint = new GeoPoint((int) (latitudeTopLeft * 1e6 + latitudeBottomRight * 1e6) / 2,
				(int) (longitudeTopLeft * 1e6 + longitudeBottomRight * 1e6) / 2);
	}

	@Override
	public Boolean call() throws Exception {
		QueryBuilder<BenzinskaDto, String> queryBuilder = benzinskaDao.queryBuilder();
		queryBuilder.setWhere(getWhereQueryPart(queryBuilder));
		queryBuilder.orderByRaw(getOrderQueryPart());
		queryBuilder.limit(Integer.valueOf(Config.RESULT_LIMIT));

		PreparedQuery<BenzinskaDto> preparedQuery = queryBuilder.prepare();
		List<BenzinskaDto> benzinske = benzinskaDao.query(preparedQuery);
		Log.i("Kita", "Nadjeno: " + benzinske.size());

		BenzinskeResultHolder.filter(benzinske, middlePoint);
		if ((benzinske != null)) {
			BenzinskeResultHolder.init(benzinske, middlePoint, context);
			return Boolean.TRUE;
		}

		return Boolean.FALSE;
	}

	private Where<BenzinskaDto, String> getWhereQueryPart(QueryBuilder<BenzinskaDto, String> queryBuilder) throws SQLException {
		Where<BenzinskaDto, String> where = queryBuilder.where();

		where.between(BenzinskaDto.LATITUDE, String.valueOf(latitudeTopLeft < latitudeBottomRight ? latitudeTopLeft : latitudeBottomRight),
				String.valueOf(latitudeTopLeft < latitudeBottomRight ? latitudeBottomRight : latitudeTopLeft));
		where.and();
		where.between(BenzinskaDto.LONGITUDE, String.valueOf(longitudeTopLeft < longitudeBottomRight ? longitudeTopLeft : longitudeBottomRight),
				String.valueOf(longitudeTopLeft < longitudeBottomRight ? longitudeBottomRight : longitudeTopLeft));
		where.and();
		where.like("bank_id", "%" + activeType + "%");

		return where;
	}

	/**
	 * Approximation - all points are in first quadrant.<br />
	 * This is just fast approximation (taking latitudes at the same level) -
	 * not real distance function but good and fast enough.<br />
	 * 1 mile in latitude != 1 mile in longitude, except at the equator!
	 */
	private String getOrderQueryPart() {
		double longitudeScale = Math.pow(Math.cos(Math.toRadians(latitudeTopLeft / 2 + latitudeBottomRight / 2)), 2);

		return "(" + (latitudeTopLeft / 2 + latitudeBottomRight / 2) + " - latitude) * (" + (latitudeTopLeft / 2 + latitudeBottomRight / 2) + " - latitude) + "
				+ longitudeScale + " * (" + (longitudeTopLeft / 2 + longitudeBottomRight / 2) + " - longitude) * ("
				+ (longitudeTopLeft / 2 + longitudeBottomRight / 2) + " - longitude) ASC";
	}

}
